package game.metalmax.animation
{
	/**
	 * CharacterSOB.as
	 * Yin Hao
	 * @version 1.0.0
	 * 
	 * Description.
	 * 
	 * Copyright (c) 2012 Yin Hao
	 * 
	 * Permission is hereby granted, free of charge, to any person obtaining a copy
	 * of this software and associated documentation files (the "Software"), to deal
	 * in the Software without restriction, including without limitation the rights
	 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	 * copies of the Software, and to permit persons to whom the Software is
	 * furnished to do so, subject to the following conditions:
	 * 
	 * The above copyright notice and this permission notice shall be included in
	 * all copies or substantial portions of the Software.
	 * 
	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	 * THE SOFTWARE.
	 */
	
	import flash.geom.Point;
	
	import game.metalmax.animation.zone.SceneZone;
	import game.metalmax.config.GameConfig;
	import game.metalmax.entity.character.Character;
	
	import showtime.framework.ai.AIHandler;
	import showtime.framework.ai.AbstractAI;
	import showtime.framework.ai.AiConfig;
	import showtime.framework.ai.CharacterAI;
	import showtime.framework.ai.IntentionType;
	import showtime.framework.engine.Direction;
	import showtime.framework.engine.World2D;
	import showtime.framework.manager.DataBaseManager;

	public class CharacterSOB extends DynamicSOB implements AIHandler
	{
		public var ai:AbstractAI = null;
	
		public var followTarget:CharacterSOB = null;
		
		protected var lastAnimationName:String = null;
	
		public function CharacterSOB(source:Character)
		{
			super(source);				
			
			configAI();
		}
		
		override public function play(animName:String, force:Boolean=false):void
		{
			lastAnimationName = getAnimationName();
			super.play(animName, force);			
			
		}
		
		override public function configAvatar():void
		{				
			super.configAvatar();
		}
		
		override public function configAI():void
		{
			super.configAI();
		
			var aiConfig:AiConfig = DataBaseManager.getInstance().read(AiConfig, Character(source).aiConfigID);
			
			if (aiConfig == null)
			{
				return;
			}
			
			ai = new CharacterAI(this);
			ai.setInterval(aiConfig.interval);
			ai.setDirection(aiConfig.direction);
			ai.setIntention(aiConfig.intentionType);
		}
		
		public function getLastAnimationName():String
		{
			return lastAnimationName;
		}
		
		override public function destroy():void
		{
			super.destroy();
			
			if (ai != null)
			{
				ai.destroy();
				ai = null;
			}
		}

		public function notify(type:String, data:Object):void
		{
			if (!active)
			{
				return;
			}
			
			switch (type)
			{
				case IntentionType.ACTIVE:
				{
					if (data == Direction.NONE)
					{
						play(source.animationName);
					}
					else
					{						
						moveTo(int(data));
					}

					break;
				}
			}
		}	
		
		override public function moveStop():void
		{
			super.moveStop();
		}
		
		override public function moveTo(direction:int):void
		{			
			var result:Boolean = false;
			
			if (running)
			{
				return;
			}
			
			switch (direction)
			{
				case Direction.BOTTOM:
				{				
					if (SceneZone(World2D.scene).map.collisionCode(getBottomTile()) == 0 && !SceneZone(World2D.scene).map.hitObject(getBottomTile()))
					{
						targetY += GameConfig.MAP_TILE_HEIGHT;
						result = true;
					}	
					
					break;
				}
				case Direction.TOP:
				{
					if (SceneZone(World2D.scene).map.collisionCode(getTopTile()) == 0 && !SceneZone(World2D.scene).map.hitObject(getTopTile()))
					{
						targetY -= GameConfig.MAP_TILE_HEIGHT;
						result = true;
					}
					
					break;
				}
				case Direction.LEFT:
				{
					if (SceneZone(World2D.scene).map.collisionCode(getLeftTile()) == 0 && !SceneZone(World2D.scene).map.hitObject(getLeftTile()))
					{
						targetX -= GameConfig.MAP_TILE_WIDTH;
						result = true;
					}
					
					break;
				}
				case Direction.RIGHT:
				{
					if (SceneZone(World2D.scene).map.collisionCode(getRightTile()) == 0 && !SceneZone(World2D.scene).map.hitObject(getRightTile()))
					{
						targetX += GameConfig.MAP_TILE_WIDTH;
						result = true;
					}
					
					break;
				}
			}			
			
			if (result)
			{				
				play(CharacterSOB.getActiveAnimationNameByDirection(direction));
				followTarget != null && (Math.abs(x - followTarget.targetX) > 0 || Math.abs(y - followTarget.targetY) > 0) && followTarget.moveTo(lastDirection);
				lastDirection = direction;			
			
			}
			else
			{
				play(CharacterSOB.getIdleAnimationNameByDirection(direction));
			}	
			
			this.direction = direction;
			running = true;				
			
			super.moveTo(direction);
		}
		
		
		public function setFollowTarget(source:Character, position:Point):void
		{			
			
		}
		
		override public function click():void
		{
			super.click();			
		} 
		
		static public function getIdleAnimationNameByDirection(direction:int):String
		{
			switch (direction)
			{
				case Direction.BOTTOM:
				{				
					return "IDLE_BOTTOM"
				}
				case Direction.TOP:
				{
					return "IDLE_TOP"
				}
				case Direction.LEFT:
				{
					return "IDLE_LEFT"
				}
				case Direction.RIGHT:
				{
					return "IDLE_RIGHT"
				}
				default:
				{
					return "IDLE_BOTTOM";	
				}				
			}	
		}	
		
		static public function getActiveAnimationNameByDirection(direction:int):String
		{
			switch (direction)
			{
				case Direction.BOTTOM:
				{				
					return "ACTIVE_BOTTOM"
				}
				case Direction.TOP:
				{
					return "ACTIVE_TOP"
				}
				case Direction.LEFT:
				{
					return "ACTIVE_LEFT"
				}
				case Direction.RIGHT:
				{
					return "ACTIVE_RIGHT"
				}
				default:
				{
					return "ACTIVE_BOTTOM";	
				}				
			}	
		}
		
		public function getDectectorPoint():Point
		{
			var nextPoint:Point = getNextPoint();
			
			switch (direction)
			{
				case Direction.BOTTOM:
				{
					nextPoint.y += GameConfig.MAP_TILE_HEIGHT;
					return nextPoint;
				}
				case Direction.TOP:
				{
					nextPoint.y -= GameConfig.MAP_TILE_HEIGHT;
					return nextPoint;
				}
				case Direction.LEFT:
				{
					nextPoint.x -= GameConfig.MAP_TILE_WIDTH;
					return nextPoint;
				}
				case Direction.RIGHT:
				{
					nextPoint.x += GameConfig.MAP_TILE_WIDTH;
					return nextPoint;
				}
				default:
				{
					return null;
				}
			}
		}
		
		public function getBackPoint():Point
		{
			switch (direction)
			{
				case Direction.BOTTOM:
				{
					return getTopTile();
				}
				case Direction.TOP:
				{
					return getBottomTile();
				}
				case Direction.LEFT:
				{
					return getRightTile();
				}
				case Direction.RIGHT:
				{
					return getLeftTile();
				}
			}
			
			return null;
		}
		
		public function getNextPoint():Point
		{
			switch (direction)
			{
				case Direction.BOTTOM:
				{
					return getBottomTile();
				}
				case Direction.TOP:
				{
					return getTopTile();
				}
				case Direction.LEFT:
				{
					return getLeftTile();
				}
				case Direction.RIGHT:
				{
					return getRightTile();
				}
			}
			
			return null;
		}

		public function getLeftTile():Point
		{
			var result:Point = getNowPoint();
			result.x -= GameConfig.MAP_TILE_WIDTH;
			return result;
		}
		
		public function getRightTile():Point
		{
			var result:Point = getNowPoint();
			result.x += GameConfig.MAP_TILE_WIDTH;
			return result;
		}
		
		public function getBottomTile():Point
		{
			var result:Point = getNowPoint();
			result.y += GameConfig.MAP_TILE_HEIGHT;
			return result;
		}
		
		public function getTopTile():Point
		{
			var result:Point = getNowPoint();
			result.y -= GameConfig.MAP_TILE_HEIGHT;
			return result;
		}
	}
}